﻿using DocumentFormat.OpenXml.ExtendedProperties;
using DocumentFormat.OpenXml.VariantTypes;
using JiebaNet.Segmenter;
using MyPinYin;
using SharpNL.Parser;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FileManager.Util
{
    internal static class WordCompare
    {
        private readonly static JiebaSegmenter _segmenter;
        public static JiebaSegmenter Segmenter=>_segmenter;

        // 唯一单词表
        private static HashSet<string> vocabulary = new HashSet<string>();

        private static HashSet<string> p_vocabulary = new HashSet<string>();

        // 单词到索引的映射
        private static Dictionary<string, int> wordToIndex= new Dictionary<string, int>();

        private static Dictionary<string,BitArray> batchFlagVectors = new Dictionary<string,BitArray>();

        //建立拼音映射

        private static Dictionary<string, int> pyToIndex = new Dictionary<string, int>();

        private static Dictionary<string, BitArray> pyFlagVectors = new Dictionary<string, BitArray>();
        static WordCompare()
        {
            _segmenter= new JiebaSegmenter();
        }


        public static Dictionary<string, BitArray> init(IEnumerable<string> phrases)
        {
            phrases=phrases.Distinct();
            // 唯一单词表
            vocabulary = new HashSet<string>();
            p_vocabulary = new HashSet<string>();
            // 单词到索引的映射
            wordToIndex = new Dictionary<string, int>();
            batchFlagVectors = new();
            pyToIndex = new Dictionary<string, int>();
            pyFlagVectors=new Dictionary<string, BitArray>();
            // Step 1: Collect all unique words
            foreach (var phrase in phrases)
            {

                var words = _segmenter.Cut(phrase);
                foreach (var word in words)
                {
                    vocabulary.Add(word);
                }
                foreach(var c in phrase.ToArray())
                {
                    var py=PinYinConverter.Get(c);
                    p_vocabulary.Add(py);
                }
            }
            // Step 2:建立单词到索引的映射
            int index = 0;
            foreach (var word in vocabulary)
            {
                wordToIndex[word] = index++;
            }
            int index2 = 0;
            foreach(var py in p_vocabulary)
            {
                pyToIndex[py] = index2++;
            }
            foreach(var phrase in phrases)
            {
                var bitArray = GeneratePhraseBitArrays(phrase);
                batchFlagVectors.Add(phrase, bitArray);
            }
            foreach (var phrase in phrases)
            {
                var bitArray = GeneratePyPhraseBitArrays(phrase);
                pyFlagVectors.Add(phrase, bitArray);
            }
            return batchFlagVectors;
        }

        /// <summary>
        /// 将短语转为按单词分词后的二进制向量
        /// </summary>
        /// <param name="phrase">短语</param>
        /// <returns>二进制数组向量</returns>
        public static BitArray GeneratePhraseBitArrays(string phrase)
        {
            var numInts = vocabulary.Count;
            BitArray bitArray=new BitArray(new bool[numInts]);
           
            var words = _segmenter.Cut(phrase);
            foreach (var word in words)
            {
                if (wordToIndex.TryGetValue(word, out int wordIndex))
                {
                    bitArray.Set(wordIndex, true);
                }
            }
            return bitArray;
        }

        public static BitArray GeneratePyPhraseBitArrays(string phrase)
        {
            var numInts = p_vocabulary.Count;
            BitArray bitArray = new BitArray(new bool[numInts]);
            foreach (var c in phrase.ToArray())
            {
                var py = PinYinConverter.Get(c);
                if (pyToIndex.TryGetValue(py, out int wordIndex))
                {
                    bitArray.Set(wordIndex, true);
                }
            }            
            return bitArray;
        }
        public static IEnumerable<string> GetSimilar(string phrase, int maxCount, double minCos = 0.3d, bool fromPy = false)
        {
            // 计算每个键值对的相似度并过滤出大于等于minCos的项
            if (!fromPy)
            {
                var ta = batchFlagVectors
.Select(a => new { Name = a.Key, Similarity = Compare(a.Value, phrase) });
                var filteredItems = ta
                    .Where(a => a.Similarity >= minCos)
                    .OrderByDescending(a => a.Similarity)
                    .Select(a => a.Name)
                    .ToList();


                // 获取前count个匹配项
                int backLength = Math.Min(maxCount, filteredItems.Count);
                return filteredItems.Take(backLength);

            }
            else
            {
                var ta = pyFlagVectors
.Select(a => new { Name = a.Key, Similarity = PyCompare(a.Value, phrase) });
                var filteredItems = ta
                    .Where(a => a.Similarity >= minCos)
                    .OrderByDescending(a => a.Similarity)
                    .Select(a => a.Name)
                    .ToList();


                // 获取前count个匹配项
                int backLength = Math.Min(maxCount, filteredItems.Count);
                return filteredItems.Take(backLength);
            }

        }


        public static double Compare(string phrase1, string phrase2)
        {
            var t1=GeneratePhraseBitArrays(phrase1);
            var t2=GeneratePhraseBitArrays(phrase2);
           
            double dotProduct = 0.0;
            double magnitudeA = 0.0;
            double magnitudeB = 0.0;
            
            for(int i = 0; i < t1.Count; i++)
            {
                if (t1[i] & t2[i])
                    dotProduct++;
                if (t1[i])
                    magnitudeA++;
                if (t2[i])
                    magnitudeB++;
            }
            magnitudeA = Math.Sqrt(magnitudeA);
            magnitudeB = Math.Sqrt(magnitudeB);
            return dotProduct / (magnitudeA * magnitudeB);
        }
        public static double PyCompare(BitArray t1, string phrase2)
        {
            var t2 = GeneratePyPhraseBitArrays(phrase2);


            double dotProduct = 0.0;
            double magnitudeA = 0.0;
            double magnitudeB = 0.0;


            for (int i = 0; i < t1.Count; i++)
            {
                if (t1[i] & t2[i])
                    dotProduct++;
                if (t1[i])
                    magnitudeA++;
                if (t2[i])
                    magnitudeB++;
            }
            magnitudeA = Math.Sqrt(magnitudeA);
            magnitudeB = Math.Sqrt(magnitudeB);
            return dotProduct / (magnitudeA * magnitudeB);
        }
        public static double Compare(BitArray t1, string phrase2)
        {
            var t2 = GeneratePhraseBitArrays(phrase2);


            double dotProduct = 0.0;
            double magnitudeA = 0.0;
            double magnitudeB = 0.0;


            for (int i = 0; i < t1.Count; i++)
            {
                if (t1[i] & t2[i])
                    dotProduct++;
                if (t1[i])
                    magnitudeA++;
                if (t2[i])
                    magnitudeB++;
            }
            magnitudeA = Math.Sqrt(magnitudeA);
            magnitudeB = Math.Sqrt(magnitudeB);
            return dotProduct / (magnitudeA * magnitudeB);
        }
    }

}
